package cn.wolfcode.service.impl;

import cn.wolfcode.common.constants.CommonConstants;
import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.CommonCodeMsg;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.Product;
import cn.wolfcode.domain.SeckillProduct;
import cn.wolfcode.domain.SeckillProductVo;
import cn.wolfcode.feign.ProductFeignApi;
import cn.wolfcode.mapper.SeckillProductMapper;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created by lanxw
 */
@Service
public class SeckillProductServiceImpl implements ISeckillProductService {
    @Autowired
    private SeckillProductMapper seckillProductMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private ProductFeignApi productFeignApi;

    @Override
    public List<SeckillProductVo> queryByTime(Integer time) {
        // TODO
        /*
            查询当前时间段的秒杀商品----List<SeckillProduct>
            查询商品详细信息----List<Product>
            封装List<SeckillProductVo>并响应
         */
        List<SeckillProduct> seckillProducts = seckillProductMapper.queryCurrentlySeckillProduct(time);
        // 判断当前场次是否有秒杀商品
        if (seckillProducts == null || seckillProducts.size() == 0) { // 没有秒杀商品
            throw new BusinessException(CommonCodeMsg.ILLEGAL_OPERATION);
        }
        // 获取秒杀商品的商品id
        List<Long> productIds = seckillProducts.stream()
                .map(sp -> sp.getProductId())
                .collect(Collectors.toList());
        // 获取 List<Product> ---远程调用 product 的服务
        Result<List<Product>> result = productFeignApi.queryByIds(productIds);
        // 判断返回的 result 是否正常
        if (result == null || result.hasError()){
            throw new BusinessException(SeckillCodeMsg.PRODUCT_SERVER_ERROR);
        }
        List<Product> products = result.getData();
        // products 转成 map
        Map<Long, Product> productMap = products.stream()
                .collect(Collectors.toMap(Product::getId, p -> p));
        // 封装 List<SeckillProductVo>
        List<SeckillProductVo> vos = new ArrayList<>();
        for (SeckillProduct seckillProduct : seckillProducts) {
            Product product = productMap.get(seckillProduct.getProductId());
            SeckillProductVo vo = new SeckillProductVo();
            BeanUtils.copyProperties(product,vo);
            BeanUtils.copyProperties(seckillProduct,vo);
            vos.add(vo);
        }
        return vos;
    }

    @Override
    public SeckillProductVo find(Integer time, Long seckillId) {
        SeckillProduct seckillProduct = seckillProductMapper.queryByTimeAndSeckillId(time,seckillId);
        if (seckillProduct == null) { // 没有秒杀商品
            throw new BusinessException(CommonCodeMsg.ILLEGAL_OPERATION);
        }
        List<Long> ids = new ArrayList<>();
        ids.add(seckillProduct.getProductId());
        Result<List<Product>> result = productFeignApi.queryByIds(ids);
        // 判断返回的 result 是否正常
        if (result == null || result.hasError()){
            throw new BusinessException(SeckillCodeMsg.PRODUCT_SERVER_ERROR);
        }
        Product product = result.getData().get(0);
        SeckillProductVo vo = new SeckillProductVo();
        BeanUtils.copyProperties(product,vo);
        BeanUtils.copyProperties(seckillProduct,vo);
        return vo;
    }

    @Override
    public int decrStockCount(Long seckillId) {
        return seckillProductMapper.decrStock(seckillId);
    }

    @Override
    public List<SeckillProductVo> queryByTimeFromCache(Integer time) {
        String key = SeckillRedisKey.SECKILL_PRODUCT_HASH.getRealKey(String.valueOf(time));
        List<Object> values = redisTemplate.opsForHash().values(key);
        List<SeckillProductVo> vos = values.stream()
                .map(vo -> JSON.parseObject((String) vo, SeckillProductVo.class))
                .collect(Collectors.toList());
        return vos;
    }

    @Override
    public SeckillProductVo findFromCache(Integer time, Long seckillId) {
        String key = SeckillRedisKey.SECKILL_PRODUCT_HASH.getRealKey(String.valueOf(time));
        Object vo = redisTemplate.opsForHash().get(key, String.valueOf(seckillId));
        return JSON.parseObject((String) vo, SeckillProductVo.class);
    }

    @Override
    public void syncStockCountToRedis(Integer time, Long seckillId) {
        int stockCount = seckillProductMapper.getStockCount(seckillId);
        if (stockCount > 0) {
            String stockCountKey = SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(String.valueOf(time));
            redisTemplate.opsForHash().put(stockCountKey,String.valueOf(seckillId),String.valueOf(stockCount));
        }
    }

    @Override
    public void incrStocCount(Long seckillId) {
        seckillProductMapper.incrStock(seckillId);
    }
}
